/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

#pragma once

#include <functional>
#include <string>
#include <vector>

#include <boost/bind/bind.hpp>
#include <boost/function.hpp>
#include <boost/signals2.hpp>
#include <highfive/H5File.hpp>

#include "DataStructure/Common/Status.h"
#include "DataStructure/Input/Constraint/ConstraintType.h"
#include "DataStructure/Input/Coordinate/CoordTypes.h"
#include "DataStructure/Input/Dynamic/DynamicType.h"
#include "DataStructure/Input/Element/ElementTypes.h"
#include "DataStructure/Input/Load/LoadTypes.h"
#include "DataStructure/Input/Material/MaterialTypes.h"
#include "DataStructure/Input/Property/PropertyTypes.h"
#include "DataStructure/Input/Table/TableTypes.h"

#include "DBManager/Database/CachePool.h"
#include "DBManager/Database/IDatabase.h"

SG_DBMANAGER_NAMESPACE_OPEN

const std::size_t FIELD_SIZE = 8;

/// @brief 数据库中心类，管理数据库的信号和槽。
class HDF5Hub : public IDatabaseHub
{
  public:
    HDF5Hub ()          = default;
    virtual ~HDF5Hub () = default;

  public:
    /// @brief 清空信号槽
    void ClearSignal () override;

    /**
     *  当调用Element的汇总信息的时候，将已有的Element的缓存信息全部都持久化到HDF5文件中。 槽函数为各Element的`DumpWriteCahce()`函数
     */
    boost::signals2::signal<void ()>                            m_elementSummarySignal;
    std::map<SG::DataStructure::FEM::ElementTypes, std::string> m_elementTypeWithIndexPathMapping;  ///< Element单元类型与路径的映射表

    /**
     * 当调用坐标系的汇总信息的时候，将已有的缓存信息全部都持久化到HDF5文件中。 槽函数为各仓库的`DumpWriteCahce()`函数
     */
    boost::signals2::signal<void ()>                          m_coordinateSummarySignal;
    std::map<SG::DataStructure::FEM::CoordTypes, std::string> m_coordinateTypeWithIndexPathMapping;  ///< Coordinate单元类型与路径的映射表

    /**
     * 当调用材料的汇总信息的时候，将已有的缓存信息全部都持久化到HDF5文件中。 槽函数为各仓库的`DumpWriteCahce()`函数
     */
    boost::signals2::signal<void ()>                             m_materialSummarySignal;
    std::map<SG::DataStructure::FEM::MaterialTypes, std::string> m_materialTypeWithIndexPathMapping;  ///< Material单元类型与路径的映射表

    /**
     * 当调用LOAD的汇总信息的时候，将已有的缓存信息全部都持久化到HDF5文件中。 槽函数为各仓库的`DumpWriteCahce()`函数
     */
    boost::signals2::signal<void ()>                        m_loadSummarySignal;
    std::map<SG::DataStructure::FEM::LoadType, std::string> m_loadTypeWithIndexPathMapping;  ///< loadinate单元类型与路径的映射表

    boost::signals2::signal<void ()>                              m_constraintSummarySignal;
    std::map<SG::DataStructure::FEM::ConstraintType, std::string> m_constraintTypeWithIndexPathMapping;

    boost::signals2::signal<void ()>                            m_rElementSummarySignal;
    std::map<SG::DataStructure::FEM::RElementType, std::string> m_rElementTypeWithIndexPathMapping;

    boost::signals2::signal<void ()>                           m_dynamicSummarySignal;
    std::map<SG::DataStructure::FEM::DynamicType, std::string> m_dynamicTypeWithIndexPathMapping;

    boost::signals2::signal<void ()>                             m_propertySummarySignal;
    std::map<SG::DataStructure::FEM::PropertyTypes, std::string> m_propertyTypeWithIndexPathMapping;

    boost::signals2::signal<void ()>                          m_tableSummarySignal;
    std::map<SG::DataStructure::FEM::TableTypes, std::string> m_tableTypeWithIndexPathMapping;

  public:
    /// @brief 获取属性到单元映射的函数指针类型
    using GetP2EFun =
        std::function<std::map<SG::DataStructure::Common::I64, std::vector<SG::DataStructure::Common::Id>> (SG::DBManager::IDatabase*)>;

    static std::vector<GetP2EFun>* s_getP2EFunList;

    static std::vector<GetP2EFun>* GetP2EFunList ()
    {
        return s_getP2EFunList;
    }

    static void ConnectGetP2E (const GetP2EFun& funp)
    {
        if (s_getP2EFunList == nullptr)
        {
            s_getP2EFunList = new std::vector<GetP2EFun>;
        }
        s_getP2EFunList->push_back (funp);
    }

  public:
    /// @brief 获取单元节点矩阵的函数指针类型
    using FunGetElementNodes = std::function<SG::Algebra::Matrix (SG::DBManager::IDatabase*)>;

    static std::map<SG::DataStructure::FEM::ElementTypes, FunGetElementNodes>* s_getElementNodesFunMap;

    static std::map<SG::DataStructure::FEM::ElementTypes, FunGetElementNodes>* GetElementNodesFunMap ()
    {
        return s_getElementNodesFunMap;
    }

    static bool ConnectGetElementNodes (SG::DataStructure::FEM::ElementTypes type, FunGetElementNodes funp)
    {
        if (s_getElementNodesFunMap == nullptr)
        {
            s_getElementNodesFunMap = new std::map<SG::DataStructure::FEM::ElementTypes, FunGetElementNodes>;
        }
        s_getElementNodesFunMap->insert ({ type, std::move (funp) });
        return true;
    }

  public:
    /// @brief 初始化单元仓库的函数指针类型
    using FunInitElementRepos = std::function<void (SG::DBManager::IDatabase*)>;

    static std::map<SG::DataStructure::FEM::ElementTypes, FunInitElementRepos>* s_initElementReposMethods;

    static std::map<SG::DataStructure::FEM::ElementTypes, FunInitElementRepos>* GetInitElementReposMethods ()
    {
        return s_initElementReposMethods;
    }

    static bool ConnectInitElementReposMethods (SG::DataStructure::FEM::ElementTypes type, FunInitElementRepos funp)
    {
        if (s_initElementReposMethods == nullptr)
        {
            s_initElementReposMethods = new std::map<SG::DataStructure::FEM::ElementTypes, FunInitElementRepos>;
        }
        s_initElementReposMethods->insert ({ type, std::move (funp) });
        return true;
    }
};

/**
 * @class HDF5Database
 * @brief 通过 HighFive 库实现的 HDF5 数据库管理类。
 *
 * HDF5Database 继承自 IDatabase，提供 HDF5 文件的操作与管理功能。
 * 支持动态注册和创建数据存储库的功能。
 */

class DBManager_DECLSPEC HDF5Database : public IDatabase
{
    friend class DatabaseFactory;  ///< DatabaseFactory 友元类，用于创建 HDF5Database 实例。
    friend class DBServiceFactory;

  public:
    /// @brief 函数指针类型，用于创建和销毁存储库。
    using NewRepositoryFunP = void* ( * ) (HDF5Database&);
    using DelRepositoryFunP = void (*) (void*);
    using ClearFun          = std::function<void ()>;

    /**
     * @struct RepoFunPInfo
     * @brief 存储函数指针，用于创建和销毁特定类型的存储库。
     */
    struct RepoFunPInfo
    {
        NewRepositoryFunP NewFunp;  ///< 函数指针，用于创建存储库。
        DelRepositoryFunP DelFunp;  ///< 函数指针，用于销毁存储库。
    };

    /**
     * @brief 析构函数，清理数据库资源。
     */
    virtual ~HDF5Database () override;

    /**
     * @brief 清除数据库并重置文件指针。
     */
    void ClearDatabase () override;

    /**
     * @brief 保存数据库并重新打开文件。
     */
    void SaveDatabase () override;

    /**
     * @brief 保存数据库。
     */
    void Disconnect () override;

    /**
     * @brief 连接数据库数据库。
     */
    void Connect () override;

    /**
     * @brief 注册存储库的创建与销毁函数指针。
     * @param key 存储库类型的哈希值。
     * @param value 包含创建与销毁函数指针的结构体。
     * @return 注册成功返回 true。
     */
    static bool RegRepoFunP (std::size_t key, RepoFunPInfo value);

    /**
     * @brief 获取 HDF5 文件的共享指针。
     */
    HighFive::File* GetFile () const;

    HDF5Hub* GetHDF5Hub ()
    {
        return dynamic_cast<HDF5Hub*> (GetHub ());
    }

    /**
     * @brief 获取缓存池引用
     * @return 缓存池引用
     */
    CachePool& GetCachePool ()
    {
        return m_cachePool;
    }

    /**
     * @brief 获取缓存池引用（const版本）
     * @return 缓存池引用
     */
    const CachePool& GetCachePool () const
    {
        return m_cachePool;
    }

  protected:
    /**
     * @brief 构造函数，使用路径和文件名初始化数据库。
     * @param foldPath 数据库文件的路径。
     * @param fileName 数据库文件的名称。
     */
    HDF5Database (std::string foldPath, std::string fileName);

    /**
     * @brief 创建特定类型的数据存储库。
     * @param typeInfo 存储库类型的信息。
     * @return 如果创建成功返回 true，否则抛出异常。
     */
    SG::DataStructure::Common::Status CreateRepository (const std::type_info& typeInfo) override;

    /**
     * @brief 获取存储库函数指针的映射表。
     * @return 存储库函数指针的映射表。
     */
    static std::map<std::size_t, RepoFunPInfo>& GetFunPInfo ();

  private:
    HighFive::File* m_FilePtr;    ///< 代表数据库的 HDF5 文件。
    CachePool       m_cachePool;  ///< 缓存池实例

    bool isConnected = false;     ///< 是否已连接数据库
};
SG_DBMANAGER_NAMESPACE_CLOSE
